package org.apache.ocean;

import java.util.ArrayList;
import java.util.List;
import java.util.SortedSet;
import java.util.concurrent.ConcurrentHashMap;

import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.lucene.document.Document;
import org.apache.ocean.util.ConcurrentLinkedHashMap;
import org.apache.ocean.util.OceanConcurrentHashMap;



/**
 *
 * @author jasonr
 */
public class DocumentCache {
  public IndexSchema indexSchema;
  public ConcurrentLinkedHashMap<DocumentKey,Document> map;
  public ConcurrentHashMap<IDVersion,List<DocumentKey>> idVersionMap;
  
  public DocumentCache(int maxSize, IndexSchema indexSchema) {
    this.indexSchema = indexSchema;
    map = new ConcurrentLinkedHashMap(maxSize);
    idVersionMap = new OceanConcurrentHashMap<IDVersion,List<DocumentKey>>();
  }
  
  public int getMaxSize() {
    return map.maxSize;
  }
  
  public int getSize() {
    return map.size();
  }
  
  public static class DocumentKey {
    private int hashCode;
    public CLong id;
    public CLong version;
    public SortedSet<String> fields;
    
    public DocumentKey(IDVersion idVersion, SortedSet<String> fields) {
      this(idVersion.id, idVersion.version, fields);
    }
    
    public DocumentKey(CLong id, CLong version, SortedSet<String> fields) {
      this.id = id;
      this.version = version;
      this.fields = fields;
      HashCodeBuilder builder = new HashCodeBuilder();
      builder.append(id);
      builder.append(version);
      builder.append(fields);
      hashCode = builder.hashCode();
    }
    
    public boolean equals(Object object) {
      if (!(object instanceof DocumentKey)) return false;
      if (object == null) return false;
      DocumentKey other = (DocumentKey)object;
      return ObjectUtils.equals(id, other.id) && ObjectUtils.equals(version, other.version) && ObjectUtils.equals(fields, other.fields);
    }
    
    public int hashCode() {
      return hashCode;
    }
  }
  
  public void remove(IDVersion idVersion) {
    idVersion.illegalArgs();
    List<DocumentKey> list = idVersionMap.get(idVersion);
    if (list != null) {
      for (DocumentKey documentKey : list) {
        map.remove(documentKey);
      }
    }
    idVersionMap.remove(idVersion);
  }
  
  public void addDocument(Document document, SortedSet<String> fields) {
    CLong id = ClusterUtil.getID(document, indexSchema);
    if (id == null) throw new IllegalArgumentException("id null");
    CLong version = ClusterUtil.getVersion(document, indexSchema);
    if (version == null) throw new IllegalArgumentException("version null");
    String shardID = ClusterUtil.getShardID(document);
    IDVersion idVersion = new IDVersion(id, version, shardID);
    DocumentKey documentKey = new DocumentKey(idVersion, fields);
    map.put(documentKey, document);
    List<DocumentKey> list = idVersionMap.get(idVersion);
    if (list == null) {
      list = new ArrayList<DocumentKey>();
      idVersionMap.put(idVersion, list);
    }
    list.add(documentKey);
  }
  
  public Document getDocument(IDVersion idVersion, SortedSet<String> fields) {
    idVersion.illegalArgs();
    DocumentKey documentKey = new DocumentKey(idVersion, fields);
    return map.get(documentKey);
  }
}
